package cc.rengu.igas.opms.common.util;

import cc.rengu.igas.opms.common.enums.RespCodeEnum;
import cc.rengu.oltp.service.model.BizException;
import org.apache.commons.codec.binary.Base64;
import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;

import javax.crypto.Cipher;
import java.io.*;
import java.net.URLEncoder;
import java.security.KeyFactory;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * 银联全渠道加签验签工具类
 * Created by 王成 on 2018/12/26.
 */
public class OpmsUpacSecurityUtil {
    /* 算法常量： SHA1 */
    private static final String ALGORITHM_SHA1 = "SHA-1";
    /* 算法常量： SHA256 */
    private static final String ALGORITHM_SHA256 = "SHA-256";
    /* 算法常量：SHA1withRSA */
    private static final String BC_PROV_ALGORITHM_SHA1RSA = "SHA1withRSA";
    /* 算法常量：SHA256withRSA */
    private static final String BC_PROV_ALGORITHM_SHA256RSA = "SHA256withRSA";
    /**
     * 编码
     */
    public static final String UTF_8_ENCODING = "UTF-8";
    public static final String SIGNMETHOD_SHA256 = "11";
    public static final String SIGNMETHOD_SM3 = "12";
    public static final String SIGNMETHOD_RSA = "01";
    public static final String AMPERSAND = "&";
    public static final String VERSION_5_1_0 = "5.1.0";

    /**
     * 对字符串进行加密
     *
     * @param data      待加密字符串
     * @param secureKey 加密证书
     * @param encoding  编码方式
     * @return 加密后的数字串
     * @throws Exception 异常
     */
    public static String encryptData(String data, String secureKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, getPublicKey(secureKey));
        byte[] encryptData = cipher.doFinal(data.getBytes(encoding));
        return new String(Base64.encodeBase64(encryptData), encoding);
    }


    /**
     * 对字符串进行加密
     *
     * @param data      待加密字符串
     * @param publicKey 加密证书
     * @param encoding  编码方式
     * @return 加密后的数字串
     * @throws Exception 异常
     */
    public static String encryptData(String data, RSAPublicKey publicKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
        cipher.init(Cipher.ENCRYPT_MODE, publicKey);
        byte[] encryptData = cipher.doFinal(data.getBytes(encoding));
        return new String(Base64.encodeBase64(encryptData), encoding);
    }

    /**
     * 对字符串进行解密
     *
     * @param encryptData 加密字符串
     * @param decryptKey  解密密钥
     * @param encoding    编码方式
     * @return 解密后的字符串
     * @throws Exception 异常
     */
    public static String decryptData(String encryptData, String decryptKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, getPrivateKey(decryptKey));
        byte[] deccryptData = cipher.doFinal(Base64.decodeBase64(encryptData.getBytes(encoding)));
        return new String(deccryptData, encoding);
    }

    /**
     * 对字符串进行解密
     *
     * @param encryptData 加密字符串
     * @param privateKey  解密密钥
     * @param encoding    编码方式
     * @return 解密后的字符串
     * @throws Exception 异常
     */
    public static String decryptData(String encryptData, RSAPrivateKey privateKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC");
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        byte[] deccryptData = cipher.doFinal(Base64.decodeBase64(encryptData.getBytes(encoding)));
        return new String(deccryptData, encoding);
    }

    /**
     * 使用签名密钥进行签名
     *
     * @param signDataMap 待签名数据
     * @param secureKey   签名私钥
     * @param encoding    编码方式
     * @return true-成功，false-失败
     * @throws Exception 异常
     */
    public static boolean signBySecureKey(Map<String, String> signDataMap, String secureKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        String signMethod = signDataMap.get("signMethod");
        if (SIGNMETHOD_SHA256.equals(signMethod)) {
            /* 将Map信息转换成key1=value1&key2=value2的形式 */
            String stringData = covertMap2String(signDataMap);
            String strBeforeSha256 = stringData + AMPERSAND + sha256X16Str(secureKey, encoding);
            String strAfterSha256 = sha256X16Str(strBeforeSha256, encoding);
            /* 设置签名域值 */
            signDataMap.put("signature", strAfterSha256);
            return true;
        } else if (SIGNMETHOD_SM3.equals(signMethod)) {
            String stringData = covertMap2String(signDataMap);
            String strBeforeSM3 = stringData + AMPERSAND + sm3X16Str(secureKey, encoding);
            String strAfterSM3 = sm3X16Str(strBeforeSM3, encoding);
            /* 设置签名域值 */
            signDataMap.put("signature", strAfterSM3);
            return true;
        } else if (SIGNMETHOD_RSA.equals(signMethod)) {
            String version = signDataMap.get("version");
            String stringData = covertMap2String(signDataMap);
            byte[] signDigest;
            if (VERSION_5_1_0.equals(version)) {
                signDigest = sha256X16(stringData, encoding);
            } else {
                signDigest = sha1X16(stringData, encoding);
            }
            Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
            st.initSign(getPrivateKey(secureKey));
            st.update(signDigest);
            byte[] byteSign = Base64.encodeBase64(st.sign());
            signDataMap.put("signature", new String(byteSign));
            return true;
        }
        return false;
    }

    private static boolean signBySecureKey(Map<String, String> signDataMap, PrivateKey secureKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        String signMethod = signDataMap.get("signMethod");
        if (SIGNMETHOD_RSA.equals(signMethod)) {
            String version = signDataMap.get("version");
            String stringData = covertMap2String(signDataMap);
            byte[] signDigest;
            if (VERSION_5_1_0.equals(version)) {
                signDigest = sha256X16(stringData, encoding);
            } else {
                signDigest = sha1X16(stringData, encoding);
            }
            Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
            st.initSign(secureKey);
            st.update(signDigest);
            byte[] byteSign = Base64.encodeBase64(st.sign());
            signDataMap.put("signature", new String(byteSign));
            return true;
        }
        return false;
    }

    /**
     * 使用验签密钥对签名进行验签
     *
     * @param signDataMap 待验签数据
     * @param secureKey   验签密钥
     * @param encoding    编码方式
     * @return true-成功，false-失败
     * @throws Exception 异常
     */
    private static boolean verifySignBySecureKey(Map<String, String> signDataMap, String secureKey, String encoding) throws Exception {
        if (Security.getProvider("BC") == null) {
            Security.addProvider(new BouncyCastleProvider());
        }
        String signMethod = signDataMap.get("signMethod");
        if (SIGNMETHOD_SHA256.equals(signMethod)) {
            /* 进行SHA256验证 */
            String stringSign = signDataMap.get("signature");
            /* 将Map信息转换成key1=value1&key2=value2的形式 */
            String stringData = covertMap2String(signDataMap);
            String strBeforeSha256 = stringData + AMPERSAND + sha256X16Str(secureKey, encoding);
            String strAfterSha256 = sha256X16Str(strBeforeSha256, encoding);
            return stringSign.equals(strAfterSha256);
        } else if (SIGNMETHOD_SM3.equals(signMethod)) {
            /* 进行SM3验证 */
            String stringSign = signDataMap.get("signature");
            /* 将Map信息转换成key1=value1&key2=value2的形式 */
            String stringData = covertMap2String(signDataMap);
            String strBeforeSM3 = stringData + AMPERSAND + sm3X16Str(secureKey, encoding);
            String strAfterSM3 = sm3X16Str(strBeforeSM3, encoding);
            return stringSign.equals(strAfterSM3);
        } else if (SIGNMETHOD_RSA.equals(signMethod)) {
            /* 进行SHA验证 */
            String stringSign = signDataMap.get("signature");
            String version = signDataMap.get("version");
            String stringData = covertMap2String(signDataMap);
            if (VERSION_5_1_0.equals(version)) {
                String strCert = signDataMap.get("signPubKeyCert");
                CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
                InputStream tIn = new ByteArrayInputStream(strCert.getBytes("ISO-8859-1"));
                X509Certificate x509Cert = (X509Certificate) cf.generateCertificate(tIn);
                if (null == x509Cert) {
                    return false;
                }
                Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA256RSA, "BC");
                st.initVerify(x509Cert.getPublicKey());
                st.update(sha256X16(stringData, encoding));
                return st.verify(Base64.decodeBase64(stringSign.getBytes(encoding)));
            } else {
                Signature st = Signature.getInstance(BC_PROV_ALGORITHM_SHA1RSA, "BC");
                st.initVerify(getPublicKey(secureKey));
                st.update(sha1X16(stringData, encoding));
                return st.verify(Base64.decodeBase64(stringSign.getBytes(encoding)));
            }
        }
        return false;
    }

    /**
     * 删除空标签字段
     *
     * @param contentData 待过滤的MAP对象
     * @return 过滤后的MAP对象
     */
    private static Map<String, String> filterBlank(Map<String, String> contentData) {
        Map<String, String> submitFromData = new HashMap<String, String>();
        Set<String> keyset = contentData.keySet();
        for (String key : keyset) {
            String value = contentData.get(key);
            if (value != null && !"".equals(value.trim())) {
                /* 对value值进行去除前后空处理 */
                submitFromData.put(key, value.trim());
            }
        }
        return submitFromData;
    }

    /**
     * 将报文字符串转换成MAP对象
     *
     * @param result 报文字符串
     * @return MAP对象
     */
    public static Map<String, String> convertResultString2Map(String result) {
        Map<String, String> map = null;
        if (result != null && !"".equals(result.trim())) {
            if (result.startsWith("{") && result.endsWith("}")) {
                result = result.substring(1, result.length() - 1);
            }
            map = parseJsonString(result);
        }
        return map;
    }

    /**
     * 将MAP对象转换成带&分隔符的JSON字符串
     *
     * @param dataMap MAP对象
     * @return 字符串
     */
    public static String covertResultMap2String(Map<String, String> dataMap) {
        TreeMap tree = new TreeMap();
        Iterator it = dataMap.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry sf = (Map.Entry) it.next();
            tree.put(sf.getKey(), sf.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf1 = new StringBuffer();
        while (it.hasNext()) {
            Map.Entry en = (Map.Entry) it.next();
            sf1.append(en.getKey() + "=" + en.getValue() + AMPERSAND);
        }
        return sf1.substring(0, sf1.length() - 1);
    }

    /**
     * 将MAP对象转换成带&分隔符的JSON字符串
     *
     * @param data MAP对象
     * @return JSON字符串
     */
    public static String covertMap2String(Map<String, String> data) {
        TreeMap<String, String> tree = new TreeMap<String, String>();
        Iterator<Map.Entry<String, String>> it = data.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            if ("signature".equals(en.getKey().trim())) {
                continue;
            }
            tree.put(en.getKey(), en.getValue());
        }
        it = tree.entrySet().iterator();
        StringBuffer sf = new StringBuffer();
        while (it.hasNext()) {
            Map.Entry<String, String> en = it.next();
            sf.append(en.getKey() + "=" + en.getValue() + AMPERSAND);
        }
        return sf.substring(0, sf.length() - 1);
    }

    /**
     * 将还分隔符&的JSON字符串转换成Map对象
     *
     * @param jsonString JSON字符串
     * @return MAP对象
     */
    public static Map<String, String> parseJsonString(String jsonString) {
        Map<String, String> map = new HashMap<String, String>();
        int len = jsonString.length();
        StringBuilder temp = new StringBuilder();
        char curChar;
        String key = null;
        boolean isKey = true;
        boolean isOpen = false;//值里有嵌套
        char openName = 0;
        if (len > 0) {
            for (int i = 0; i < len; i++) {// 遍历整个带解析的字符串
                curChar = jsonString.charAt(i);// 取当前字符
                if (isKey) {// 如果当前生成的是key
                    if (curChar == '=') {// 如果读取到=分隔符
                        key = temp.toString();
                        temp.setLength(0);
                        isKey = false;
                    } else {
                        temp.append(curChar);
                    }
                } else {// 如果当前生成的是value
                    if (isOpen) {
                        if (curChar == openName) {
                            isOpen = false;
                        }
                    } else {//如果没开启嵌套
                        if (curChar == '{') {//如果碰到，就开启嵌套
                            isOpen = true;
                            openName = '}';
                        }
                        if (curChar == '[') {
                            isOpen = true;
                            openName = ']';
                        }
                    }
                    if (curChar == '&' && !isOpen) {// 如果读取到&分割符,同时这个分割符不是值域，这时将map里添加
                        putKeyValueToMap(temp, isKey, key, map);
                        temp.setLength(0);
                        isKey = true;
                    } else {
                        temp.append(curChar);
                    }
                }
            }
            putKeyValueToMap(temp, isKey, key, map);
        }
        return map;
    }

    /**
     * 将还分隔符&的kv字符串转换成Map对象
     *
     * @param kvString
     * @return
     */
    public static Map<String, Object> parseKvString(String kvString) {
        Map<String, Object> map = new HashMap<String, Object>();
        int len = kvString.length();
        StringBuilder temp = new StringBuilder();
        char curChar;
        String key = null;
        boolean isKey = true;
        boolean isOpen = false;//值里有嵌套
        char openName = 0;
        if (len > 0) {
            for (int i = 0; i < len; i++) {// 遍历整个带解析的字符串
                curChar = kvString.charAt(i);// 取当前字符
                if (isKey) {// 如果当前生成的是key
                    if (curChar == '=') {// 如果读取到=分隔符
                        key = temp.toString();
                        temp.setLength(0);
                        isKey = false;
                    } else {
                        temp.append(curChar);
                    }
                } else {// 如果当前生成的是value
                    if (isOpen) {
                        if (curChar == openName) {
                            isOpen = false;
                        }
                    } else {//如果没开启嵌套
                        if (curChar == '{') {//如果碰到，就开启嵌套
                            isOpen = true;
                            openName = '}';
                        }
                        if (curChar == '[') {
                            isOpen = true;
                            openName = ']';
                        }
                    }
                    if (curChar == '&' && !isOpen) {// 如果读取到&分割符,同时这个分割符不是值域，这时将map里添加
                        putKeyValueToMapObj(temp, isKey, key, map);
                        temp.setLength(0);
                        isKey = true;
                    } else {
                        temp.append(curChar);
                    }
                }
            }
            putKeyValueToMapObj(temp, isKey, key, map);
        }
        return map;
    }

    /**
     * 将KEY及VALUE值设置对Map对象
     *
     * @param temp  VALUE值
     * @param isKey 是否为KEY标识
     * @param key   KEY值
     * @param map   MAP对象
     */
    private static void putKeyValueToMap(StringBuilder temp, boolean isKey, String key, Map<String, String> map) {
        if (isKey) {
            key = temp.toString();
            if (key.length() == 0) {
                throw new RuntimeException("String format illegal");
            }
            map.put(key, "");
        } else {
            if (key.length() == 0) {
                throw new RuntimeException("String format illegal");
            }
            map.put(key, temp.toString());
        }
    }

    /**
     * 将KEY及VALUE值设置对Map对象
     *
     * @param temp
     * @param isKey
     * @param key
     * @param map
     */
    private static void putKeyValueToMapObj(StringBuilder temp, boolean isKey, String key, Map<String, Object> map) {
        if (isKey) {
            key = temp.toString();
            if (key.length() == 0) {
                throw new RuntimeException("String format illegal");
            }
            map.put(key, "");
        } else {
            if (key.length() == 0) {
                throw new RuntimeException("String format illegal");
            }
            map.put(key, temp.toString());
        }
    }


    /**
     * 对客户密码进行加密
     *
     * @param acctNo    账号
     * @param pinData   密码
     * @param secureKey 加密证书密钥
     * @param encoding  编码方式
     * @return 加密后的密码
     * @throws Exception 异常
     */
    public static String encryptPinData(String acctNo, String pinData, String secureKey, String encoding) throws Exception {
        byte[] pinByte = pinToPinBlock(pinData);
        if (acctNo.length() == 11) {
            acctNo = "00" + acctNo;
        } else if (acctNo.length() == 12) {
            acctNo = "0" + acctNo;
        }
        byte[] panByte = formatPan(acctNo);
        byte[] pinDataByte = new byte[8];
        for (int i = 0; i < 8; i++) {
            pinDataByte[i] = (byte) (pinByte[i] ^ panByte[i]);
        }
        String encryptData = encryptData(new String(pinDataByte, encoding), secureKey, encoding);
        return new String(Base64.encodeBase64(encryptData.getBytes()), encoding);
    }

    /**
     * 账号处理
     *
     * @param acctNo 账号
     * @return 账号
     */
    private static byte[] formatPan(String acctNo) {
        int tPanLen = acctNo.length();
        byte[] tByte = new byte[8];
        int temp = tPanLen - 13;
        tByte[0] = (byte) 0x00;
        tByte[1] = (byte) 0x00;
        for (int i = 2; i < 8; i++) {
            String a = acctNo.substring(temp, temp + 2);
            tByte[i] = (byte) Integer.parseInt(a, 16);
            temp = temp + 2;
        }
        return tByte;
    }

    /**
     * 将密码转换成PINBLOCK
     *
     * @param pinData 密码
     * @return PINGBLOCK
     */
    private static byte[] pinToPinBlock(String pinData) {
        int tTemp = 1;
        int tPinLen = pinData.length();
        byte[] tByte = new byte[8];
        tByte[0] = (byte) Integer.parseInt(Integer.toString(tPinLen), 10);
        if (tPinLen % 2 == 0) {
            for (int i = 0; i < tPinLen; ) {
                String a = pinData.substring(i, i + 2);
                tByte[tTemp] = (byte) Integer.parseInt(a, 16);
                if (i == (tPinLen - 2)) {
                    if (tTemp < 7) {
                        for (int x = (tTemp + 1); x < 8; x++) {
                            tByte[x] = (byte) 0xff;
                        }
                    }
                }
                tTemp++;
                i = i + 2;
            }
        } else {
            for (int i = 0; i < tPinLen - 1; ) {
                String a;
                a = pinData.substring(i, i + 2);
                tByte[tTemp] = (byte) Integer.parseInt(a, 16);
                if (i == (tPinLen - 3)) {
                    String b = pinData.substring(tPinLen - 1) + "F";
                    tByte[tTemp + 1] = (byte) Integer.parseInt(b, 16);
                    if ((tTemp + 1) < 7) {
                        for (int x = (tTemp + 2); x < 8; x++) {
                            tByte[x] = (byte) 0xff;
                        }
                    }
                }
                tTemp++;
                i = i + 2;
            }
        }
        return tByte;
    }

    /**
     * 对字符串进行SHA256计算并转换成16进制编码
     *
     * @param data     待计算的字符串
     * @param encoding 编码方式
     * @return 转换后的字符串
     */
    public static String sha256X16Str(String data, String encoding) throws Exception {
        MessageDigest md = MessageDigest.getInstance(ALGORITHM_SHA256);
        md.reset();
        md.update(data.getBytes(encoding));
        byte[] bytes = md.digest();
        StringBuilder sha256StrBuff = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
                sha256StrBuff.append("0").append(Integer.toHexString(0xFF & bytes[i]));
            } else {
                sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
            }
        }
        return sha256StrBuff.toString();
    }

    /**
     * 对字符串进行SM3计算并转换成16进制编码
     *
     * @param data     待计算的字符串
     * @param encoding 编码方式
     * @return 转换后的字符串
     */
    public static String sm3X16Str(String data, String encoding) throws Exception {
        SM3Digest sm3 = new SM3Digest();
        sm3.update(data.getBytes(encoding), 0, data.getBytes(encoding).length);
        byte[] bytes = new byte[sm3.getDigestSize()];
        sm3.doFinal(bytes, 0);
        StringBuilder sm3StrBuff = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
                sm3StrBuff.append("0").append(Integer.toHexString(0xFF & bytes[i]));
            } else {
                sm3StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
            }
        }
        return sm3StrBuff.toString();
    }

    /**
     * 对字符串进行SHA1计算并转换成16进制编码
     *
     * @param data     待计算的字符串
     * @param encoding 编码方式
     * @return 转换后的字符串
     */
    public static byte[] sha1X16(String data, String encoding) throws Exception {
        MessageDigest md = MessageDigest.getInstance(ALGORITHM_SHA1);
        md.reset();
        md.update(data.getBytes(encoding));
        byte[] bytes = md.digest();
        StringBuilder sha1StrBuff = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
                sha1StrBuff.append("0").append(Integer.toHexString(0xFF & bytes[i]));
            } else {
                sha1StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
            }
        }
        return sha1StrBuff.toString().getBytes(encoding);
    }

    /**
     * 对字符串进行SHA256计算并转换成16进制编码
     *
     * @param data     待计算的字符串
     * @param encoding 编码方式
     * @return 转换后的字符串
     */
    public static byte[] sha256X16(String data, String encoding) throws Exception {
        MessageDigest md = MessageDigest.getInstance(ALGORITHM_SHA256);
        md.reset();
        md.update(data.getBytes(encoding));
        byte[] bytes = md.digest();
        StringBuilder sha256StrBuff = new StringBuilder();
        for (int i = 0; i < bytes.length; i++) {
            if (Integer.toHexString(0xFF & bytes[i]).length() == 1) {
                sha256StrBuff.append("0").append(Integer.toHexString(0xFF & bytes[i]));
            } else {
                sha256StrBuff.append(Integer.toHexString(0xFF & bytes[i]));
            }
        }
        return sha256StrBuff.toString().getBytes(encoding);
    }

    /**
     * 公钥转换
     *
     * @param key 公钥字符串
     * @return 公钥
     * @throws Exception 异常
     */
    public static PublicKey getPublicKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 私钥转换
     *
     * @param key 私钥字符串
     * @return 私钥
     * @throws Exception 异常
     */
    public static PrivateKey getPrivateKey(String key) throws Exception {
        byte[] keyBytes;
        keyBytes = (new BASE64Decoder()).decodeBuffer(key);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
        return privateKey;
    }

    /**
     * 将Map存储的对象，转换为key=value&key=value的字符,value值做urlEncode
     *
     * @param requestParam 请求报文MAP
     * @param coder        编码格式
     * @return upac请求报文
     */
    public static String getRequestParamString(Map<String, String> requestParam, String coder) {
        if (null == coder || "".equals(coder)) {
            coder = "UTF-8";
        }
        StringBuffer sf = new StringBuffer("");
        String reqstr = "";
        if (null != requestParam && 0 != requestParam.size()) {
            for (Map.Entry<String, String> en : requestParam.entrySet()) {
                try {
                    sf.append(en.getKey()
                            + "="
                            + (null == en.getValue() || "".equals(en.getValue()) ? "" : URLEncoder
                            .encode(en.getValue(), coder)) + "&");
                } catch (UnsupportedEncodingException e) {
                    return "";
                }
            }
            reqstr = sf.substring(0, sf.length() - 1);
        }
        return reqstr;
    }

    /**
     * 获取证书序列号
     *
     * @param filePath
     * @param passwd
     * @return
     */
    public static String getCertIdFromCertFile(String filePath, String passwd) {
        List<String> aliasList = new ArrayList<>();
        String keyAlias = null;
        FileInputStream fileInputStream = null;
        try {
            KeyStore keyStore = KeyStore.getInstance("PKCS12");
            fileInputStream = new FileInputStream(filePath);

            keyStore.load(fileInputStream, passwd.toCharArray());

            fileInputStream.close();
            Enumeration list = keyStore.aliases();
            if (list.hasMoreElements()) {
                keyAlias = (String) list.nextElement();
            }
            X509Certificate cert = (X509Certificate) keyStore.getCertificate(keyAlias);
            return cert.getSerialNumber().toString();
        } catch (Exception e) {

        } finally {
            if (null != fileInputStream) {
                try {
                    fileInputStream.close();
                } catch (IOException e) {

                }
            }
        }
        return null;
    }

    /**
     * 获取cer证书序列号
     *
     * @param filePath
     * @return
     */
    public static String getPubCertIdFromCertFile(String filePath) {
        File certFile = new File(filePath);
        if (certFile.exists()) {
            if (filePath.endsWith(".cer")) {
                InputStream inputStream = null;
                try {
                    inputStream = new FileInputStream(filePath);
                    CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                    X509Certificate x509Certificate = (X509Certificate) certificateFactory.generateCertificate(inputStream);
                    if (null != inputStream) {
                        inputStream.close();
                    }

                    return x509Certificate.getSerialNumber().toString();
                } catch (Exception e) {

                } finally {
                    if (null != inputStream) {
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                        }
                    }
                    return null;
                }
            } else {
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * 组http自动提交表单
     *
     * @param reqUrl   请求地址
     * @param hiddens  表单键值
     * @param encoding 编码
     * @return 构造好的交易表单
     */
    public static String createFormHtml(String reqUrl, Map<String, String> hiddens, String encoding) {
        StringBuilder sf = new StringBuilder();
        sf.append("<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=").append(encoding).append("\"/></head><body>");
        sf.append("<form id = \"pay_form\" action=\"").append(reqUrl).append("\" method=\"post\">");
        if (null != hiddens && hiddens.size() != 0) {
            Set<Map.Entry<String, String>> set = hiddens.entrySet();
            for (Map.Entry<String, String> entry : set) {
                String key = entry.getKey();
                String value = entry.getValue();
                sf.append("<input type=\"hidden\" name=\"").append(key).append("\" id=\"").append(key).append("\" value=\"").append(value).append("\"/>");
            }
        }
        sf.append("</form>");
        sf.append("</body>");
        sf.append("<script type=\"text/javascript\">");
        sf.append("document.all.pay_form.submit");
        sf.append("</script>");
        sf.append("</html>");
        return sf.toString();
    }


    /**
     * 从公钥证书文件中获取公钥
     *
     * @param certFilePath 公钥证书文件路径
     * @return 公钥证书
     * @throws Exception 异常
     */
    public static X509Certificate getCertificateFromCertFile(String certFilePath) throws Exception {
        File certFile = new File(certFilePath);
        if (certFile.exists()) {
            try (InputStream inputStream = new FileInputStream(certFilePath)) {
                CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
                return (X509Certificate) certificateFactory.generateCertificate(inputStream);
            } catch (Exception e) {
                throw new BizException(RespCodeEnum.CERT_LOAD_INVALID.getRespCode(), RespCodeEnum.CERT_LOAD_INVALID.getRespDesc());
            }
        } else {
            throw new BizException(RespCodeEnum.CERT_LOAD_INVALID.getRespCode(), RespCodeEnum.CERT_LOAD_INVALID.getRespDesc());
        }
    }

    /**
     * 从公钥证书文件中获取公钥
     *
     * @param certFilePath 公钥证书文件路径
     * @return 公钥证书
     * @throws Exception 异常
     */
    public static KeyStore getCertificateFromPfxFile(String certFilePath, String password) throws Exception {
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fileInputStream = new FileInputStream(certFilePath)) {
            if ((null == password) || "".equals(password.trim())) {
                keyStore.load(fileInputStream, null);
            } else {
                keyStore.load(fileInputStream, password.toCharArray());
            }
            return keyStore;
        } catch (Exception e) {
            throw new BizException(RespCodeEnum.CERT_LOAD_INVALID.getRespCode(), RespCodeEnum.CERT_LOAD_INVALID.getRespDesc());
        }
    }
}
